/**
  ******************************************************************************
  * @file    bsp.c
  * @author  ashuai0110
  * @version V2.0
  * @date    2024-09-05
  * @brief   板级支持包
  *
  ******************************************************************************
  * @attention
  *
  * 版权声明:内容为编者(ashuai0110)原创,使用请注明出处,当然,你也可以不这样做^_^
  * 出处链接:https://gitee.com/ashuai0110/mcu_reuse_development_module.git
  *
  * Change Logs:
  * Date          Author        Notes
  * 2024-09-05    ashuai0110    完成基本内容
  *
  ******************************************************************************
  */

/* 包含头文件-----------------------------------------------------------------*/
#include "bsp.h"
#include <string.h>

/* 私有宏定义-----------------------------------------------------------------*/
#define FLASH_PAGE_SIZE                 (1024u) /* FLASH页大小 */
#define FLASH_PROGRAM_SIZE              (4u) /* FLASH单次写入大小 */

/* 私有类型定义---------------------------------------------------------------*/

/* 私有变量-------------------------------------------------------------------*/

/* 全局变量-------------------------------------------------------------------*/

/* 私有函数原型---------------------------------------------------------------*/


/**
  * @brief  系统时钟初始化72MHz(HSE)
  *
  * @param  None
  *
  * @retval None
  */
static void rcc_clock_config(void)
{
    RCC_DeInit();

    RCC_HSEConfig(RCC_HSE_ON); /* 打开外部高速时钟HSE */
    while(RESET == RCC_GetFlagStatus(RCC_FLAG_HSERDY)); /* 等待时钟稳定 */

    RCC_HCLKConfig(RCC_SYSCLK_Div1); /* AHB clock(HCLK) = SYSCLK/1 (max:72MHz) */

    RCC_PCLK1Config(RCC_HCLK_Div2); /* APB1 clock(PCLK1) = HCLK/2 (max:36MHz) */

    RCC_PCLK2Config(RCC_HCLK_Div1); /* APB2 clock(PCLK2) = HCLK/1 (max:72MHz) */

    FLASH_SetLatency(FLASH_Latency_2); /* FLASH 2等待周期 */
    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); /* 使能FLASH预取缓冲区 */

    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); /* SYSCLK == 72MHz  PLLCLK = 8MHz*9 */
    RCC_PLLCmd(ENABLE); /* 使能PLL */
    while(RESET == RCC_GetFlagStatus(RCC_FLAG_PLLRDY)); /* 等待PLL稳定 */
    
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); /* 选择PLLCLK作为SYSCLK时钟源 */
    while(0x08 != RCC_GetSYSCLKSource()); /* 等待SYSCLK时钟源切换完成 */

    SysTick_Config(72000); /* systick初始化周期1ms */
}

/**
  * @brief  NVIC初始化
  *
  * @param  None
  *
  * @retval None
  */
static void nvic_config(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); /* 设置中断优先级组4 */
    
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

/**
  * @brief  GPIO初始化
  *
  * @param  None
  *
  * @retval None
  */
static void gpio_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* 开启GPIO时钟 */
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; /* 设置引脚号 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* 设置引脚模式 */
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /* 设置引脚速度 */
    GPIO_Init(GPIOA, &GPIO_InitStructure); /* 初始化GPIO */
    
    GPIO_WriteBit(GPIOA, GPIO_Pin_8, Bit_SET); /* LED */
}

/**
  * @brief  USART1初始化
  *
  * @param  None
  *
  * @retval None
  */
static void usart1_config(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); /* 打开串口时钟 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); /* 打开GPIO时钟 */
    
    /* USART Tx的GPIO配置 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; /* 设置引脚号 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; /* 设置引脚模式 复用推挽 */
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /* 设置引脚速度 */
    GPIO_Init(GPIOA, &GPIO_InitStructure); /* 初始化GPIO */
    /* USART Rx的GPIO配置 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; /* 设置引脚号 */
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; /* 设置引脚模式 浮空输入 */
    GPIO_Init(GPIOA, &GPIO_InitStructure); /* 初始化GPIO */

    USART_DeInit(USART1);

    USART_InitStructure.USART_BaudRate = 115200; /* 波特率 */
    USART_InitStructure.USART_WordLength = USART_WordLength_8b; /* 数据长度 8bit */
    USART_InitStructure.USART_StopBits = USART_StopBits_1; /* 停止位 1bit */
    USART_InitStructure.USART_Parity = USART_Parity_No; /* 校验位 无 */
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; /* 硬件流控 无 */
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; /* 工作模式 接收和发送 */
    USART_Init(USART1, &USART_InitStructure); /* 初始化串口 */

    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); /* 使能接收中断 */

    USART_Cmd(USART1, ENABLE); /* 开启串口 */
}

/**
  * @brief  BSP初始化
  *
  * @param  None
  *
  * @retval None
  */
void bsp_init(void)
{
    nvic_config();
    rcc_clock_config();
    gpio_config();
    usart1_config();
}

/**
  * @brief  led翻转
  *
  * @param  None
  *
  * @retval None
  */
void bsp_led_toggle(void)
{
    GPIOA->ODR ^= GPIO_Pin_8;
}

/**
  * @brief  擦除flash
  * @param  startAddr : 起始地址
  * @param  bytes     : 擦除总字节数量
  * @retval 0:擦除成功  1:擦除失败
  */
uint8_t bsp_flash_erase(uint32_t startAddr, uint32_t bytes)
{
    uint8_t ret = 0;
    uint8_t pageNum = (bytes % FLASH_PAGE_SIZE == 0) ? (bytes / FLASH_PAGE_SIZE) : (bytes / FLASH_PAGE_SIZE + 1);
    
    __disable_irq();
    FLASH_Unlock();
    while(pageNum--)
    {
        if(FLASH_COMPLETE != FLASH_ErasePage(startAddr))
        {
            ret = 1;
            break;
        }
        startAddr += FLASH_PAGE_SIZE;
    }
    FLASH_Lock();
    __enable_irq();

    return ret;
}

/**
  * @brief  读flash
  * @param  startAddr : 起始地址
  * @param  pBuf      : 数据存储区
  * @param  len       : 读取数量byte
  * @retval 0:读取成功
  */
uint8_t bsp_flash_read(uint32_t startAddr, void *pBuf, uint32_t len)
{
    __disable_irq();
    memcpy(pBuf, (void *)startAddr, len);
    __enable_irq();
    
    return 0;
}

/**
  * @brief  写flash
  * @param  startAddr : 起始地址
  * @param  pBuf      : 数据缓冲区
  * @param  len       : 写入数量byte
  * @retval 0:写入成功  1:写入失败
  */
uint8_t bsp_flash_write(uint32_t startAddr, void *pBuf, uint32_t len)
{
    uint8_t ret = 0;
    uint32_t *dataTmp;
    
    dataTmp = (uint32_t *)pBuf; /* 类型转换为4字节类型 */
    /* 将写入数量除以单次写入大小计算写入次数并且不满4字节的写入也计入1次写入 */
    len = (len % FLASH_PROGRAM_SIZE == 0) ? (len / FLASH_PROGRAM_SIZE) : (len / FLASH_PROGRAM_SIZE + 1);

    __disable_irq();
    FLASH_Unlock();
    while(len--)
    {
        if(FLASH_COMPLETE != FLASH_ProgramWord(startAddr, *dataTmp))
        {
            ret = 1;
            break;
        }
        startAddr += 4;
        dataTmp++;
    }
    FLASH_Lock();
    __enable_irq();

    return ret;
}
